﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Soft
{
    [TypeConverter(typeof(StructObjectTypeConverter<DateTimeRange>))]
    [Serializable]
    public struct DateTimeRange : IRange<DateTime, TimeSpan>, IComparable<IRange<DateTime, TimeSpan>>
    {


        /// <summary>
        /// 开始时间，结束时间      结束时间-开始时间
        /// </summary>
        /// <param name="start"></param>
        /// <param name="end"></param>
        public DateTimeRange(DateTime start, DateTime end)
        {
            this.mStart = start;
            this.mEnd = end;
            this.mSpan = this.mStart - this.mEnd;
        }


        /// <summary>
        /// 开始时间 + 时间间隔= 结束时间
        /// </summary>
        /// <param name="start"></param>
        /// <param name="span"></param>
        public DateTimeRange(DateTime start, TimeSpan span)
        {
            this.mStart = start;
            this.mEnd = start.Add(span);
            this.mSpan = span;
        }


        /// <summary>
        /// 开始时间
        /// </summary>
        [Description("Start time of the range")]
        public DateTime Start
        {
            get
            {
                return this.mStart;
            }
            set
            {
                if (this.mStart != value)
                {
                    this.mStart = value;
                    this.mSpan = this.mEnd - this.mStart;
                }
            }
        }


        /// <summary>
        /// 结束时间
        /// </summary>
        [Description("End time of the range")]
        public DateTime End
        {
            get
            {
                return this.mEnd;
            }
            set
            {
                if (this.mEnd != value)
                {
                    this.mEnd = value;
                    this.mSpan = this.mEnd - this.mStart;
                }
            }
        }

 
        /// <summary>
        /// 时间间隔
        /// </summary>
        [Browsable(false)]
        public TimeSpan Span
        {
            get
            {
                return this.mSpan;
            }
        }


        /// <summary>
        /// 比较两个时间段 是否相等（比较开始时间&&比较结束时间）
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public int CompareTo(IRange<DateTime, TimeSpan> other)
        {
            int num = this.Start.CompareTo(other.Start);
            if (num == 0)
            {
                num = this.End.CompareTo(other.End);
            }
            return num;
        }


        /// <summary>
        /// 当前时间是否在包含的时间判断内
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Include(DateTime value)
        {
            return this.Start <= value && this.End >= value;
        }


        /// <summary>
        /// 当前时间是否在包含的时间判断内
        /// </summary>
        /// <param name="range"></param>
        /// <returns></returns>
        public bool Include(DateTimeRange range)
        {
            return this.Start <= range.Start && this.End >= range.End;
        }


        /// <summary>
        /// 判断时间片段是否有重叠
        /// </summary>
        /// <param name="range"></param>
        /// <returns></returns>
        public bool Overlap(DateTimeRange range)
        {
            return this.Start <= range.End && this.End >= range.Start;
        }


        /// <summary>
        /// 判断时间片段是否有交叉
        /// </summary>
        /// <param name="range"></param>
        /// <returns></returns>
        public DateTimeRange Intersection(DateTimeRange range)
        {
            DateTimeRange empty = DateTimeRange.Empty;
            if (this.Overlap(range))
            {
                empty.Start = ((this.Start >= range.Start) ? this.Start : range.Start);
                empty.End = ((this.End <= range.End) ? this.End : range.End);
            }
            return empty;
        }


        /// <summary>
        /// 添加时间
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public DateTimeRange Add(DateTime value)
        {
            if (this.Start > value)
            {
                return new DateTimeRange(value, this.End);
            }
            if (this.End < value)
            {
                return new DateTimeRange(this.Start, value);
            }
            return new DateTimeRange(this.Start, this.End);
        }


        /// <summary>
        /// 添加时间
        /// </summary>
        /// <param name="range"></param>
        /// <returns></returns>
        public DateTimeRange Add(DateTimeRange range)
        {
            return this.Add(range.Start).Add(range.End);
        }


        /// <summary>
        /// 添加时间
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public DateTimeRange Add(TimeUnitItem item)
        {
            return new DateTimeRange(this.Start.Add(item), this.End.Add(item));
        }


        /// <summary>
        /// 转化为字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Format("{0} -> {1}", this.Start.ToDateTimeString(false), this.End.ToDateTimeString(false));
        }


        /// <summary>
        /// 判断是否相等
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (obj != null && obj.GetType() == typeof(DateTimeRange))
            {
                DateTimeRange dateTimeRange = (DateTimeRange)obj;
                return this.Start == dateTimeRange.Start && this.End == dateTimeRange.End;
            }
            return false;
        }


        /// <summary>
        /// GetHashCode
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this.Start.GetHashCode() ^ this.End.GetHashCode();
        }


        /// <summary>
        /// 重载相等操作符
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(DateTimeRange a, DateTimeRange b)
        {
            return a.Equals(b);
        }


        /// <summary>
        /// 重载不等于操作符
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(DateTimeRange a, DateTimeRange b)
        {
            return !a.Equals(b);
        }


        /// <summary>
        /// 空的时间片段
        /// </summary>
        public static readonly DateTimeRange Empty = new DateTimeRange
        {
            Start = DateTime.MinValue,
            End = DateTime.MinValue
        };


        private DateTime mStart;

        private DateTime mEnd;

        private TimeSpan mSpan;


    }
}
